# from aliyunsdkcore.acs_exception.exceptions import ServerException as AliyunServerException
from django.db.models import ProtectedError
from django.db.utils import DatabaseError
from rest_framework.exceptions import (
    APIException,
    AuthenticationFailed,
    ValidationError,
    ErrorDetail
)
from rest_framework.status import (
    HTTP_500_INTERNAL_SERVER_ERROR
)

# from rest_framework_simplejwt.exceptions import InvalidToken

# 客户端异常
CLIENT_ERROR = 4000  # 默认异常
PARAMETER_ERROR = 4001  # 参数异常
DATA_ERROR = 4002  # 数据异常
NOT_ALLOWED = 4003  # 方法不允许
NOT_FOUND = 4004  # 资源不存在
UNAUTHORIZED = 4010  # 认证失败
PASSWORD_VERIFICATION_ERROR = 4011  # 账号密码校验失败
TOKEN_EXPIRED = 4012  # TOKEN 过期

# 服务端异常
SERVER_ERROR = 5000  # 默认异常
DATABASE_ERROR = 5001  # 数据库异常
REMOTE_ERROR = 5002  # 远程调用异常
FUNCTION_ERROR = 5003  # 方法错误


class BaseExceptions(Exception):
    status = HTTP_500_INTERNAL_SERVER_ERROR

    def __init__(self, error, data=None, error_code=SERVER_ERROR):
        self.error = error
        self.data = data
        self.error_code = error_code

    def __str__(self):
        return self.error


class CommonError(BaseExceptions):
    pass


def get_error_detail(e):
    """
    :param e: ErrorDetail类, 或者ErrorDetail组成的list or dict
    :return: 错误信息 list->list, dict->dict, ErrorDetail->{code: str}, Other->str
    """
    if isinstance(e, list):
        ret = list(map(get_error_detail, e))
        return ret
    if isinstance(e, dict):
        for k, v in e.items():
            e[k] = get_error_detail(v)
        return e
    if isinstance(e, ErrorDetail):
        return str(e)
    return str(e)


# APIException 异常返回
def rest_framework_exceptions_response(ex: APIException):
    assert isinstance(ex, APIException), \
        'ex必须为rest_framework.exceptions.APIException类'
    status = ex.status_code
    msg = get_error_detail(ex.detail)

    # if isinstance(ex, InvalidToken):
    #     # token不合法或登录过期
    #     msg = get_error_detail(ex.detail['detail'])
    #     code = TOKEN_EXPIRED
    if isinstance(ex, AuthenticationFailed):
        # 认证失败, 一般是账号密码错误
        code = PASSWORD_VERIFICATION_ERROR
    elif isinstance(ex, ValidationError):
        # 序列化错误, 一般是参数错误
        code = PARAMETER_ERROR
    else:
        code = CLIENT_ERROR
    return msg, code, status


# DatabaseError 异常返回
def database_error_response(ex: DatabaseError):
    assert isinstance(ex, DatabaseError), \
        'ex必须是django.db.utils.DatabaseError类'
    code = DATABASE_ERROR
    status = HTTP_500_INTERNAL_SERVER_ERROR
    if isinstance(ex, ProtectedError):
        msg = "删除失败: 该条数据与其他数据有相关绑定"
    else:
        msg = "数据库异常, 请联系管理员"
    return msg, code, status


# YnetBaseException 异常返回
def custom_error_response(ex: BaseExceptions):
    assert isinstance(ex, BaseExceptions), 'ex必须是BaseException类'
    return ex.error, ex.error_code, ex.status


def exception_response(ex):
    if isinstance(ex, APIException):
        return rest_framework_exceptions_response(ex)
    if isinstance(ex, DatabaseError):
        return database_error_response(ex)
    if isinstance(ex, BaseExceptions):
        return custom_error_response(ex)
    # if isinstance(ex, AliyunServerException):
    #     return ex.get_error_msg(), REMOTE_ERROR, ex.get_http_status

    msg = f'服务器内部错误, 请联系管理员, 错误信息: <{type(ex).__name__}: {str(ex)}>'
    code = SERVER_ERROR
    status = HTTP_500_INTERNAL_SERVER_ERROR
    return msg, code, status
